﻿// <copyright file="Localization.cs" company="Lu Studio">
// Copyright (c) Lu Studio. All rights reserved.
// </copyright>
// <author>lu qi</author>
// <createTime>2021-06-19</createTime>

namespace ElfKit.Common
{
    using ElfKit.Common.Properties;
    using System;
    using System.Globalization;
    using System.Resources;

    /// <summary>
    /// 本地化.
    /// </summary>
    public static class Localization
    {
        #region GetString

        /// <summary>
        /// 获得<typeparamref name="TResource"/>中名称为<paramref name="resourceName"/>的字符串.
        /// </summary>
        /// <typeparam name="TResource">资源<see cref="Type"/>实例.</typeparam>
        /// <param name="resourceName">资源名称.</param>
        /// <param name="culture"><see cref="CultureInfo"/>实例.</param>
        /// <returns>字符串.</returns>
        /// <exception cref="ArgumentException"><paramref name="resourceName"/> is null or string.Empty or WhiteSpace.</exception>
        /// <exception cref="ArgumentException"><paramref name="resourceName"/>not found <paramref name="resourceName"/> in type <typeparamref name="TResource"/>.</exception>
        public static string GetString<TResource>(string resourceName, CultureInfo culture = null)
        {
            return GetString(typeof(TResource), resourceName, culture);
        }

        /// <summary>
        /// 获得<paramref name="resourceType"/>中名称为<paramref name="resourceName"/>的字符串.
        /// </summary>
        /// <param name="resourceType"><see cref="Type"/>实例.</param>
        /// <param name="resourceName">资源名称.</param>
        /// <param name="culture"><see cref="CultureInfo"/>实例.</param>
        /// <returns>字符串.</returns>
        /// <exception cref="ArgumentNullException"><paramref name="resourceType"/>is null.</exception>
        /// <exception cref="ArgumentException"><paramref name="resourceName"/> is null or string.Empty or WhiteSpace.</exception>
        /// <exception cref="ArgumentException"><paramref name="resourceName"/>not found <paramref name="resourceName"/> in type <paramref name="resourceType"/>.</exception>
        public static string GetString(
            Type resourceType,
            string resourceName,
            CultureInfo culture = null)
        {
            if (resourceType is null)
            {
                throw new ArgumentNullException(nameof(resourceType));
            }

            if (string.IsNullOrWhiteSpace(resourceName))
            {
                throw new ArgumentException(Resources.ResourceNameIsNullOrWhiteSpace, nameof(resourceName));
            }

            culture ??= Env.GetCurrentCulture();
            ////获得资源工厂
            ResourceManager rm = GetResourceManager(resourceType);
            ////获得字符串
            string result = rm.GetString(resourceName, culture);
            return string.IsNullOrEmpty(result)
                ? throw new ArgumentException(
                    string.Format(
                        culture,
                        Resources.NotFoundResourceString,
                        resourceType.FullName,
                        resourceName),
                    nameof(resourceName))
                : result;
        }

        /// <summary>
        /// 获得<paramref name="attribute"/>对应的字符串.
        /// </summary>
        /// <param name="attribute"><see cref="ResourceAttribute"/>实例.</param>
        /// <returns>字符串.</returns>
        /// <exception cref="ArgumentNullException"><paramref name="attribute"/>is null.</exception>
        public static string GetString(ResourceAttribute attribute)
        {
            Guard.NotNull(attribute, nameof(attribute));

            return GetString(attribute.ResourceType, attribute.ResourceName, attribute.Culture);
        }

        #endregion

        #region Format

        /// <summary>
        /// 从<typeparamref name="TResource"/>中获得名称为<paramref name="resourceName"/>的格式字符串并按<paramref name="args"/>进行格式化.
        /// </summary>
        /// <typeparam name="TResource">资源<see cref="Type"/>实例.</typeparam>
        /// <param name="resourceName">资源名称.</param>
        /// <param name="args">参数数组.</param>
        /// <returns>字符串.</returns>
        /// <exception cref="ArgumentException"><paramref name="resourceName"/> is null or string.Empty or WhiteSpace.</exception>
        /// <exception cref="ArgumentException"><paramref name="resourceName"/>not found <paramref name="resourceName"/> in type <typeparamref name="TResource"/>.</exception>
        public static string Format<TResource>(string resourceName, params string[] args)
        {
            return Format<TResource>(Env.GetCurrentCulture(), resourceName, args);
        }

        /// <summary>
        /// 从<typeparamref name="TResource"/>中获得名称为<paramref name="resourceName"/>的格式字符串并按<paramref name="args"/>进行格式化.
        /// </summary>
        /// <typeparam name="TResource">资源<see cref="Type"/>实例.</typeparam>
        /// <param name="provider"><see cref="IFormatProvider"/>实例.</param>
        /// <param name="resourceName">资源名称.</param>
        /// <param name="args">参数数组.</param>
        /// <returns>字符串.</returns>
        /// <exception cref="ArgumentNullException"><paramref name="provider"/>is null.</exception>
        /// <exception cref="ArgumentException"><paramref name="resourceName"/> is null or string.Empty or WhiteSpace.</exception>
        /// <exception cref="ArgumentException"><paramref name="resourceName"/>not found <paramref name="resourceName"/> in type <typeparamref name="TResource"/>.</exception>
        public static string Format<TResource>(IFormatProvider provider, string resourceName, params string[] args)
        {
            Guard.NotNull(provider, nameof(provider));

            string format = GetString<TResource>(resourceName);
            return string.Format(provider, format, args);
        }

        /// <summary>
        /// 从<paramref name="resourceType"/>中获得名称为<paramref name="resourceName"/>的格式字符串并按<paramref name="args"/>进行格式化.
        /// </summary>
        /// <param name="provider"><see cref="IFormatProvider"/>实例.</param>
        /// <param name="resourceType"><see cref="Type"/>实例.</param>
        /// <param name="resourceName">资源名称.</param>
        /// <param name="args">参数数组.</param>
        /// <returns>字符串.</returns>
        /// <exception cref="ArgumentNullException"><paramref name="provider"/>is null.</exception>
        /// <exception cref="ArgumentNullException"><paramref name="resourceType"/>is null.</exception>
        /// <exception cref="ArgumentException"><paramref name="resourceName"/> is null or string.Empty or WhiteSpace.</exception>
        /// <exception cref="ArgumentException"><paramref name="resourceName"/>not found <paramref name="resourceName"/> in type <paramref name="resourceType"/>.</exception>
        public static string Format(IFormatProvider provider, Type resourceType, string resourceName, params string[] args)
        {
            Guard.NotNull(provider, nameof(provider));

            string format = GetString(resourceType, resourceName);
            return string.Format(provider, format, args);
        }

        /// <summary>
        /// 从<paramref name="resourceType"/>中获得名称为<paramref name="resourceName"/>的格式字符串并按<paramref name="args"/>进行格式化.
        /// </summary>
        /// <param name="resourceType"><see cref="Type"/>实例.</param>
        /// <param name="resourceName">资源名称.</param>
        /// <param name="args">参数数组.</param>
        /// <returns>字符串.</returns>
        /// <exception cref="ArgumentNullException"><paramref name="resourceType"/>is null.</exception>
        /// <exception cref="ArgumentException"><paramref name="resourceName"/> is null or string.Empty or WhiteSpace.</exception>
        /// <exception cref="ArgumentException"><paramref name="resourceName"/>not found <paramref name="resourceName"/> in type <paramref name="resourceType"/>.</exception>
        public static string Format(Type resourceType, string resourceName, params string[] args)
        {
            return Format(Env.GetCurrentCulture(), resourceType, resourceName, args);
        }

        #endregion

        #region 内部函数

        /// <summary>
        /// 获得<paramref name="resourceType"/>对于的字符串.
        /// </summary>
        /// <param name="resourceType"><see cref="Type"/>资源类型.</param>
        /// <returns><see cref="ResourceManager"/>实例.</returns>
        private static ResourceManager GetResourceManager(Type resourceType)
        {
            return InternalCache.Get(
                () => string.Concat(typeof(Localization).FullName, Constant.Strings.Pipe, resourceType.FullName),
                () => new ResourceManager(resourceType));
        }

        #endregion
    }
}